#!/usr/bin/python

import json
import os

from sdk.mcn import occi_ext
from occi.exceptions import HTTPError
import so


class MyBackend(occi_ext.Backend):

    def create(self, entity, extras):
        token = extras['token']
        tenant = extras['tenant_name']
        attributes = entity.attributes
        self._validate_attributes(attributes)
        self.so = so.ServiceOrchestrator(token, tenant, attributes)
        self.so.so_e.design()
        entity.actions = [occi_ext.DEPLOY_ACTION]

    def _validate_attributes(self, attributes):
        cp = os.path.dirname(os.path.abspath(__file__))
        man_dir = os.path.abspath(os.path.join(cp, '../data/'))
        manifest_path = os.path.join(man_dir, 'service_manifest.json')
        with open(manifest_path, 'r') as f:
            manifest_str = f.read()
        manifest = json.loads(manifest_str)
        attrs_exp = set(manifest['service_attributes'].keys())
        attrs_rec = set(attributes.keys())
        if attrs_exp != attrs_rec:
            msg = (('Unexpected or missing attributes.\n'
                    'Expected attributes: %s.\n'
                    'Received attributes: %s') % (list(attrs_exp),
                                                  list(attrs_rec)))
            raise HTTPError(400, msg)

    def retrieve(self, entity, extras):
        if occi_ext.DEPLOY_ACTION in entity.actions:
            entity.attributes['occi.mcn.stack.state'] = 'uninitialized'
            entity.attributes['occi.mcn.stack.id'] = 'N/A'
        else:
            states, stack_ids, stack_output = self.so.so_e.state()
            state = 'UNKNOWN'
            if occi_ext.PROVISION_ACTION in entity.actions:
                if 'CREATE_IN_PROGRESS' in states:
                    state = 'CREATE_IN_PROGRESS'
                else:
                    state = 'CREATE_COMPLETE'
            if len(entity.actions) < 1:  # provision state
                if 'UPDATE_IN_PROGRESS' in states:
                    state = 'UPDATE_IN_PROGRESS'
                else:
                    state = 'UPDATE_COMPLETE'
            entity.attributes['occi.mcn.stack.state'] = state

            entity.attributes['occi.mcn.stack.id'] = '[' + \
                stack_ids[0] + ', ' + stack_ids[1] + ']'

            if stack_output is not None:
                for output in stack_output:
                    for kv in output:
                        entity.attributes[
                            kv['output_key']] = kv['output_value']

    def update(self, old, new, extras):
        # TODO: attributes would need to be defined by a mixin.
        old.attributes.update(new.attributes)
        self.so.so_e.update(old, new, extras)

    def delete(self, entity, extras):
        self.so.so_e.dispose()

    # Actions

    def deploy_me(self, entity, attributes, extras):
        self.so.so_e.deploy()
        entity.actions = [occi_ext.PROVISION_ACTION]

    def provision_me(self, entity, attributes, extras):
        self.so.so_e.provision()
        entity.actions = []

application = occi_ext.Application(MyBackend())

if __name__ == '__main__':
    from wsgiref.simple_server import make_server
    httpd = make_server('localhost', 8051, application)
    httpd.serve_forever()
